package core.net;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.io.IOException;
import java.net.*;

import core.domein.TCPDataListener;

/**
 * Klasse die een server opzet volgens het TCP protocol
 * @author Vanpoucke Sven
 *
 */
public class TCPServer implements Runnable
{
	private List<TCPClient> clients = new ArrayList<TCPClient>();
	private ServerSocket server;
	private TCPDataListener listener;
	private ExecutorService threadExecutor = Executors.newCachedThreadPool();
	
	/**
	 * Constructor
	 * @param port Poort op welke er moet geluisterd worden
	 */
	public TCPServer(int port)
	{
		try
		{
			server = new ServerSocket(port);
		} catch (IOException e)
		{
			e.printStackTrace();
		}
	}
	
	/**
	 * TCPDataListener toevoegen aan alle clients die aanwezig zijn op de server
	 * @param listener TCPDataListener die moet worden toegevoegd
	 */
	public void addTCPDataListener(TCPDataListener listener)
	{
		this.listener = listener;
		for(TCPClient client : clients)
			client.addTCPDataListener(listener);
	}
	
	/**
	 * Methode die wordt aangeroepen wanneer een client connect. Wordt doorgestuurd aan actieve listener
	 * @param client Client die geconnect is
	 */
	private void fireClientConnected(TCPClient client)
	{
		listener.clientConnected(client);
	}
	
	/**
	 * Wacht op nieuwe client om te verbinden, en handelt deze verbinding verder af
	 */
	public void run()
	{
		while(true)
		{
			try
			{
				
				Socket clientSocket = server.accept();
				TCPClient client = new TCPClient(clientSocket);
				clients.add(client);
				client.addTCPDataListener(listener);
				threadExecutor.execute(client);
				fireClientConnected(client);
			} catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * Data verzenden naar een bepaalde client
	 * @param client Client naar welke de data moet worden verzonden
	 * @param data Data welke moet verzonden worden naar de client
	 */
	public void sendDataToClient(TCPClient client, Object data)
	{
		client.sendData(data);
	}
	
	/**
	 * Data verzenden naar alle clients
	 * @param data Data welke moet verzonden worden
	 */
	public void sendDataToAll(Object data)
	{
		for(TCPClient client : clients)
			client.sendData(data);
	}
	
	/**
	 * Data verzenden naar iedereen buiten een bepaalde client
	 * @param data Data die moet worden verzonden
	 * @param sender Client die moet worden genegeerd
	 */
	public void sendDataToAllButClient(Object data, TCPClient sender)
	{
		for(TCPClient client : clients)
			if (client != sender)
				client.sendData(data);
	}
	
	/**
	 * Methode die wordt aangeroepen wanneer een client disconnect
	 * @param client Client die disconnect
	 */
	public void disconnectClient(TCPClient client)
	{
		clients.remove(client);
		
	}
}
